import java.util.*;
import java.io.*;
import java.net.*;

/**
 * @author "Adam &amp; JP"
 * This class sends and receives messages.
 *
 */
public class PostOffice {
	
	private LinkedList<Message> pendingDelivery;
	private Address localAddress;
	private HashMap<Integer, Address> idToAddress;
	private Thread receiveThread;
	private ReceiveWorker receiver;

	/** The default constructor. */
	PostOffice(Address address)
	throws PostalException
	{	pendingDelivery = new LinkedList<Message> ();
		localAddress = address;
		idToAddress = new HashMap<Integer,Address> ();
		
		addAddress (localAddress);

		//  Set up the receiving loop.
		try
		{	receiveThread = new Thread (receiver = new ReceiveWorker (this));
			receiveThread.start ();
		}
		catch (IOException e)
		{	System.err.println ("Error creating receiver thread: " + e); 
			throw new PostalException (localAddress);
		}
	}//PostOffice Constructor
	
	public synchronized void addAddress (Address addr)
	{	idToAddress.put (addr.getID (), addr); }

	public int getPort () { return localAddress.getPort (); }
	
	/** Place a message into the delivery queue.  Used only by the delivery 
	 * thread. */
	public void enqueueMsg (Message msg)
	{	synchronized (pendingDelivery)
		{	pendingDelivery.addLast (msg);
			pendingDelivery.notify ();
		}
	}
/**
 * @param m Message to be sent to Address, see message class.
 * @param dest Address of destination for Message.
 * @throws PostalException for errors in send method.
 */
	
	public synchronized void send(Message m, Address dest) 
	throws PostalException 
	{	try
		{	Socket sock = new Socket (dest.getStringIP () , dest.getPort ());
			ObjectOutputStream oos = new ObjectOutputStream (
				sock.getOutputStream ());
			m.setSrc (localAddress);
			oos.writeObject (m);
			oos.flush ();
		}
		catch (IOException e)
		{	System.err.println ("Error sending message: " + e);
			throw new PostalException (dest);
		}
	}//send
	
/**	
 * @return returns the content of the received message.
 * @throws PostalException for errors in the receive method.
 */
	public Message receive() 
	throws InterruptedException
	{	synchronized (pendingDelivery)
		{	while (pendingDelivery.size () == 0) { pendingDelivery.wait (); }
			Message result = pendingDelivery.removeFirst ();
			return result;
		}
	}//receive
}//PostOffice Class
